//
// Created by vivi on 14/04/2018.
//

#pragma once

#include "collisionobj.h"
#include "VPly/vply.h"
#include <cmath>
#include <algorithm>
#include "../constant/constants.h"
#include "../util/eigenutil.h"

namespace HairEngine {
	class BoxCollisionObject: public CollisionObject {
	Public:
		BoxCollisionObject(const Eigen::Affine3f & transform):
				CollisionObject(transform) {}

		BoxCollisionObject(const Eigen::Affine3f & transform, const Eigen::Affine3f & previousTransform, const float t):
				CollisionObject(transform, previousTransform, t) {}

		Eigen::AlignedBox3f boundingBox() const override {
			return Eigen::AlignedBox3f(Eigen::Vector3f(-1.0f, -1.0f, -1.0f), Eigen::Vector3f(1.0f, 1.0f, 1.0f));
		}

		float modelDistance(const Eigen::Vector3f & modelPos, Eigen::Vector3f *outGradientPtr = nullptr) const override  {
			float x = std::abs(modelPos.x());
			float y = std::abs(modelPos.y());
			float z = std::abs(modelPos.z());

			if (outGradientPtr) {
				if (x > y && x > z)
					*outGradientPtr = { modelPos.x() < 0.0f ? -1.0f : 1.0f , 0.0f, 0.0f };
				else if (y > x && y > z)
					*outGradientPtr = { 0.0f, modelPos.y() < 0.0f ? -1.0f : 1.0f, 0.0f };
				else
					*outGradientPtr = { 0.0f, 0.0f, modelPos.z() < 0.0f ? -1.0f : 1.0f };
			}

			return std::max(std::max(x, y), z) - 1.0f;
 		}

		std::ostream & vplyStream(std::ostream & os) const override {
			VPly::writeBox(
					os,
					EigenUtility::toVPlyMatrix4f(localToWorldTransform.matrix()),
					VPly::VPlyIntAttr("type", VPlyOptions::CollisionObject_)
			);
			return os;
		}
	};
}
